package service

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"project-info/src/model"
	"strings"
	"time"

	"github.com/golang-jwt/jwt/v4"
)

type OIDCClientService struct {
	client *http.Client
}

type TokenResponse struct {
	AccessToken  string `json:"access_token"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int    `json:"expires_in"`
	RefreshToken string `json:"refresh_token"`
	IDToken      string `json:"id_token"`
	Scope        string `json:"scope"`
}

type UserInfoRole struct {
	RoleID   int64  `json:"role_id"`
	RoleName string `json:"role_name"`
}

type UserInfo struct {
	Sub               string         `json:"sub"`
	Name              string         `json:"name"`
	PreferredUsername string         `json:"preferred_username"`
	Roles             []UserInfoRole `json:"roles"`
	Permissions       []string       `json:"permissions"`
}

func NewOIDCService() *OIDCClientService {
	return &OIDCClientService{
		client: &http.Client{
			Timeout: 30 * time.Second,
		},
	}
}

// 交换授权码获取令牌
func (s *OIDCClientService) ExchangeCodeForTokens(code, redirectURI string) (*TokenResponse, error) {
	tokenURL := fmt.Sprintf("%s/oidc/token", model.C.OIDCClientConfig.Issuer)

	data := url.Values{}
	data.Set("grant_type", "authorization_code")
	data.Set("code", code)
	data.Set("redirect_uri", redirectURI)
	data.Set("client_id", model.C.OIDCClientConfig.ClientID)
	data.Set("client_secret", model.C.OIDCClientConfig.ClientSecret)

	req, err := http.NewRequest("POST", tokenURL, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err := s.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("token exchange failed with status: %d", resp.StatusCode)
	}

	var tokenResp TokenResponse
	if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
		return nil, err
	}

	return &tokenResp, nil
}

// 刷新令牌
func (s *OIDCClientService) RefreshToken(refreshToken string) (*TokenResponse, error) {
	tokenURL := fmt.Sprintf("%s/oidc/token", model.C.OIDCClientConfig.Issuer)

	data := url.Values{}
	data.Set("grant_type", "refresh_token")
	data.Set("refresh_token", refreshToken)
	data.Set("client_id", model.C.OIDCClientConfig.ClientID)
	data.Set("client_secret", model.C.OIDCClientConfig.ClientSecret)

	req, err := http.NewRequest("POST", tokenURL, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err := s.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("token refresh failed with status: %d", resp.StatusCode)
	}

	var tokenResp TokenResponse
	if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
		return nil, err
	}

	return &tokenResp, nil
}

// 获取用户信息
func (s *OIDCClientService) GetUserInfo(accessToken string) (*UserInfo, error) {
	userinfoURL := fmt.Sprintf("%s/oidc/userinfo", model.C.OIDCClientConfig.Issuer)

	req, err := http.NewRequest("GET", userinfoURL, nil)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Authorization", "Bearer "+accessToken)

	resp, err := s.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("userinfo request failed with status: %d", resp.StatusCode)
	}

	var userInfo UserInfo
	if err := json.NewDecoder(resp.Body).Decode(&userInfo); err != nil {
		return nil, err
	}

	return &userInfo, nil
}

// 验证JWT令牌
func (s *OIDCClientService) ValidateToken(tokenString string) (*jwt.MapClaims, error) {
	// 获取JWKS
	jwksURL := fmt.Sprintf("%s/oidc/.well-known/jwks.json", model.C.OIDCClientConfig.Issuer)
	resp, err := s.client.Get(jwksURL)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// 解析JWKS并验证令牌
	// 这里需要实现JWKS解析和RSA公钥验证逻辑
	// 为简化示例，这里省略具体实现

	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		// 在实际应用中，这里应该从JWKS获取公钥
		return []byte("your-rsa-public-key"), nil
	})

	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		return &claims, nil
	}

	return nil, fmt.Errorf("invalid token")
}
